/*
 * @(#)AutomaticTaskHandler.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;

import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsVersion;
import com.dcivision.dms.core.DocumentOperationManager;
import com.dcivision.dms.dao.DmsDocumentDAObject;
import com.dcivision.dms.dao.DmsVersionDAObject;
import com.dcivision.dms.dao.MtmDocumentVersionDAObject;
import com.dcivision.form.bean.FormSubmission;
import com.dcivision.form.core.FormSubmissionManager;
import com.dcivision.form.dao.FormSubmissionDAObject;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.MessageResourcesFactory;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWorkflowChildParentProgress;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.MtmWorkflowTrackInterruptReq;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowProgressAttachment;
import com.dcivision.workflow.bean.WorkflowRecord;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.dao.MtmWorkflowChildParentProgressDAObject;
import com.dcivision.workflow.dao.MtmWorkflowDynamicUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressSystemObjectDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressUserRecordDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.MtmWorkflowTrackInterruptReqDAObject;
import com.dcivision.workflow.dao.WorkflowProgressAttachmentDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowRecordDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;
import com.dcivision.workflow.web.MaintWorkflowProgressForm;
/**
 * AutomaticTaskHandler.java
 * 
 * This class is responsible for handling automatic task and the End Step. This
 * class is not supposed to be initialized and used by your own code as it
 * relies on the scheduler.
 * 
 * @author Rollo Chan
 * @company DCIVision Limited
 * @creation date 06/10/2003
 * @version $Revision: 1.50.2.5 $
 * @see com.dcivision.workflow.core.WorkflowProgressListener#actionPerformed
 */
public class AutomaticTaskHandler implements StatefulJob {
  
  public static final String REVISION = "$Revision: 1.50.2.5 $";
  
  protected Log log = LogFactory.getLog(this.getClass().getName());
  
  public static final String AUTOMATIC_TASK_LISTENER_EKY = GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO + "L";
  
  public static final String AUTOMATIC_TASK_STATE_KEY = "PROCESS_STATE";
  
  public AutomaticTaskHandler(){
  }
  /**
   * This is not supposed to be invoked by your own code.
   * 
   * @param context The JobExecutionContext object
   * @throws JobExecutionException
   */
  public void execute(JobExecutionContext context) throws JobExecutionException {
    
    // Check the state of current task, if it has completed, break to return immediately.
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    String taskState = context.getJobDetail().getJobDataMap().getString(AUTOMATIC_TASK_STATE_KEY);
    if (!Utility.isEmpty(taskState) && GlobalConstant.TRUE.equals(taskState)) {
      return;
    }
    
    Connection conn = null;
    
    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_TASK;
    String errorMessage = "";
    
    boolean isLocalConnection = false;
    try{
      conn = (java.sql.Connection)context.getJobDetail().getJobDataMap().get("connection");
      if(conn == null){
        isLocalConnection = true;
        conn = DataSourceFactory.getConnection();
      }
      
      SessionContainer sessionCon = new SessionContainer();
      
      WorkflowProgress progress = (WorkflowProgress)context.getJobDetail().getJobDataMap().get("workflowProgress");
      Integer userID = (Integer)context.getJobDetail().getJobDataMap().get("userID");
      
      UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionCon, conn);
      sessionCon.setUserRecord((UserRecord) userRecordDAO.getObjectByID(userID));
      sessionCon.setUserIPAddress("127.0.0.1");
      sessionCon.setByPassPermission(true);
      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionCon.getUserRecordID())) {
        trigerEventUserID = sessionCon.getUserRecordID();
      }
      
      if (!Utility.isEmpty(sessionCon.getUserIPAddress())) {        
        serverName = sessionCon.getUserIPAddress();
      }      
      errorMessage =  "AutomaticTaskHandler.java -- Track ID: " + progress.getTrackID() + 
                      ", Workflow Progress ID : " + progress.getID() +
                      ", Workflow Step ID: " + progress.getWorkflowStepID() +
                      "<br> ";
      /*************************************************************
       *  get Event Log Information End
       *************************************************************/
      
      if (WorkflowStep.ACTION_TYPE_SYSTEM_AUTO.equals(progress.getWorkflowStepSource().getActionType())) {
          WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionCon, conn);
          progressManager.executeAutomaticTask(progress.getWorkflowStepSource(), progress);
          String action = progressManager.getCurrentProgressStatus();
          
          //progress.setCancelFlag(GlobalConstant.FALSE);//simon_del
          //progress.setCompleteFlag(GlobalConstant.FALSE);//simon_del
          //progress.setStatus(action);
          //log.debug("workflow progress: "+progress);
          //* prepare a workflow progress form for accomplish of the submit step
          MaintWorkflowProgressForm progressForm = new MaintWorkflowProgressForm();
          //progressForm.setFormData(progress);//simon_del
          if (WorkflowProgress.STATUS_PENDING.equals(progress.getStatus())) {
            log.debug(progress.getStatus());
            progress.setCancelFlag(GlobalConstant.FALSE);//simon_add
            progress.setCompleteFlag(GlobalConstant.FALSE);//simon_add
            progress.setStatus(action);
            progressForm.setFormData(progress);//simon_add
            progressManager.accomplishWorkflowProgressByUser(progressForm);
          }
          if(isLocalConnection){
            conn.commit();
          }
      } else if (WorkflowStep.ACTION_TYPE_END.equals(progress.getWorkflowStepSource().getActionType())) {
//        try {
          WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionCon, conn);
          WorkflowRetrievalManager retrievalManager = new WorkflowRetrievalManager(sessionCon, conn);
          WorkflowOperationManager operationManager = new WorkflowOperationManager(sessionCon, conn);
          MtmWorkflowChildParentProgressDAObject childWorkflowParentProgressDAO = new MtmWorkflowChildParentProgressDAObject(sessionCon, conn);
          WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionCon, conn);
          MtmWorkflowProgressSystemObjectDAObject mtmWfProgSysObjDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionCon, conn);
          MtmWorkflowTrackInterruptReqDAObject  workflowTrackInterruptReqDAO = new MtmWorkflowTrackInterruptReqDAObject(sessionCon, conn);
          MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, conn);
          
          //progressManager.executeAutomaticTask(progress.getWorkflowStepSource(), progress);
          String action = WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT;
          
          progress.setCancelFlag(GlobalConstant.FALSE);
          progress.setCompleteFlag(GlobalConstant.TRUE);
          progress.setStatus(action);
          //log.debug("workflow progress: "+progress);
          
          //* prepare a workflow progress form for accomplish of the submit step
          MaintWorkflowProgressForm progressForm = new MaintWorkflowProgressForm();
          progressForm.setFormData(progress);
          
          progressManager.accomplishWorkflowProgressByUser(progressForm);
          
          List pendingList = retrievalManager.getPendingProgressListByTrackID(progress.getTrackID());
          
          boolean bPending = false;
          for (int i=0; i<pendingList.size(); i++) {
            WorkflowProgress pendingProgress = (WorkflowProgress) pendingList.get(i);
            WorkflowStep pendingStep = pendingProgress.getWorkflowStepSource();
            
            if (!WorkflowStep.ACTION_TYPE_END.equals(pendingStep.getActionType()) && !"trigger stop workflow routine".equals(pendingStep.getStepName())) {
              bPending = true;
            }
          }
          
          if (!bPending) {
            //* notify all parent workflow to start again
            List parentWorkflowList = childWorkflowParentProgressDAO.getListByTrackID(progress.getTrackID());
            for (int i=0; i<parentWorkflowList.size(); i++) {
              MtmWorkflowChildParentProgress tmp = (MtmWorkflowChildParentProgress) parentWorkflowList.get(i);
              WorkflowProgress parentProgress = (WorkflowProgress) progressDAO.getObjectByID(tmp.getParentWorkflowProgressID());
              
              Object workflowObj =null;
              MtmWorkflowProgressSystemObject relatedObj = (MtmWorkflowProgressSystemObject)mtmWfProgSysObjDAO.getObjectByTrackIDObjectID(progress.getTrackID(), null);
              if(!Utility.isEmpty(relatedObj)){
                
                java.util.Map dataMap = (java.util.Map)relatedObj.getParameterObject();
                workflowObj = dataMap.get("WORKFLOW_OBJECT");
              }
              //  If it is a workflow interruption subworkflow
              if(!Utility.isEmpty(workflowObj)&&workflowObj instanceof MtmWorkflowTrackInterruptReq){
                
                MtmWorkflowTrackInterruptReq tmpInterruptReq = (MtmWorkflowTrackInterruptReq)workflowObj;
                MtmWorkflowTrackInterruptReq interruptReq = (MtmWorkflowTrackInterruptReq)workflowTrackInterruptReqDAO.getObjectByID(tmpInterruptReq.getID());
                if (WorkflowProgress.STATUS_PENDING.equals(interruptReq.getInterruptStatus())) {
                  
                  // When dissent the interrupt request, cancel Lock for Progresses
                  if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString())|| MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_STOP.equals(interruptReq.getInterruptType().toString())) {
                    List progressList = new ArrayList();
                    if (MtmWorkflowTrackInterruptReq.INTERRUPT_TYPE_ROLLBACK.equals(interruptReq.getInterruptType().toString())) {
                      progressList = retrievalManager.getLockedProgressList(parentProgress.getTrackID(), interruptReq.getTargetStepID());
                    } else {
                      progressList = retrievalManager.getLockedProgressList(parentProgress.getTrackID(),null);
                    }
                    log.debug("The Locked progress ::::" + progressList.size());
                    for (int k = 0; k < progressList.size(); k++) {
                      WorkflowProgress currentProgress = (WorkflowProgress)progressList.get(k);
                      log.debug("Have Lock Progress      " + k + ":::::" + currentProgress.getID());
                      currentProgress.setStatus(WorkflowProgress.STATUS_PENDING);
                      currentProgress =(WorkflowProgress) progressDAO.updateObject(currentProgress);
                      
                      //                      Update currentProgress related User record;
                      List progressUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(currentProgress.getID());
                      for (int h = 0; !Utility.isEmpty(progressUserRecordList) && h < progressUserRecordList.size(); h++) {
                        MtmWorkflowProgressUserRecord progressUserRecord = (MtmWorkflowProgressUserRecord)progressUserRecordList.get(h);
                        progressUserRecord.setWorkflowAction(WorkflowProgress.STATUS_PENDING);
                        progressUserRecord = (MtmWorkflowProgressUserRecord)progressUserRecordDAO.updateObject(progressUserRecord);
                      }
                    }
                  } else {
                    parentProgress.setStatus(WorkflowProgress.STATUS_PENDING);
                    parentProgress =(WorkflowProgress) progressDAO.updateObject(parentProgress);
                    //                    Update currentProgress related User record;
                    List progressUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(parentProgress.getID());
                    for (int h = 0; !Utility.isEmpty(progressUserRecordList) && h < progressUserRecordList.size(); h++) {
                      MtmWorkflowProgressUserRecord progressUserRecord = (MtmWorkflowProgressUserRecord)progressUserRecordList.get(h);
                      progressUserRecord.setWorkflowAction(WorkflowProgress.STATUS_PENDING);
                      progressUserRecord = (MtmWorkflowProgressUserRecord)progressUserRecordDAO.updateObject(progressUserRecord);
                    }
                  }  
                  
                  interruptReq.setInterruptStatus(WorkflowProgress.STATUS_GENERAL_ACCOMPLISHMENT);
                  workflowTrackInterruptReqDAO.updateObject(interruptReq);
                }
              } // If it is a normal subworkflow
              else {
                parentProgress.setCancelFlag(GlobalConstant.FALSE);
                parentProgress.setCompleteFlag(GlobalConstant.FALSE);
                parentProgress.setStatus(action);
                progressForm.setFormData(parentProgress);
                
                progressManager.accomplishWorkflowProgressByUser(progressForm);
              }
            }
            
            
            //* set all step as completed
            operationManager.completeWorkflowTrack(progress.getTrackID());
            
            //###############################
            //
            //   File attachement to DMS
            //
            //###############################
            fileAttachmentToDMS(progress.getTrackID(), conn, sessionCon);
          }
          if(isLocalConnection){
            conn.commit();
          }
      }
      
      // Record the completed flag at the end of this task.
      context.getJobDetail().getJobDataMap().put(AUTOMATIC_TASK_STATE_KEY, GlobalConstant.TRUE);
    } catch (ApplicationException appEx) {
      /***********************************
       *  Record the Event Log.
       ***********************************/
      
      if (ErrorConstant.WORKFLOW_TASK_ALREADY_COMPLETED.equals(appEx.getMsgCode())
          || ErrorConstant.WORKFLOW_TRACK_ALREADY_COMPLETED.equals(appEx.getMsgCode())
          || ErrorConstant.WORKFLOW_TRACK_ALREADY_STOPPED.equals(appEx.getMsgCode())) {
        context.getJobDetail().getJobDataMap().put(AUTOMATIC_TASK_STATE_KEY, GlobalConstant.TRUE);
      }
      
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, appEx.toString() );
      
      log.error(appEx, appEx);
    } catch (Exception e) {
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, e.toString() );
      
      log.error(e, e);    
    } finally {
      if(isLocalConnection){
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      }
    }
  }
  /**
   * Insert user record for assign user for given workflow progress , database connection and SessionContainer
   * 
   * @param workflowProgress The workflow progress
   * @param conn The database connection
   * @param sessionCon
   * @throws ApplicationException
   * @see com.dcivision.workflow.bean.MtmWorkflowStepUserActor
   */
  private void insertUserRecordForAssignUser(WorkflowProgress workflowProgress, Connection conn, SessionContainer sessionCon)throws ApplicationException {
    
    MtmWorkflowStepUserActorDAObject mtmWorkflowStepUserActorDAObject = new MtmWorkflowStepUserActorDAObject(sessionCon, conn);
    MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, conn);
    MtmWorkflowDynamicUserActorDAObject dynamicUserActorDAO = new MtmWorkflowDynamicUserActorDAObject(sessionCon, conn);
    WorkflowProgressDAObject workflowProgessDAO = new WorkflowProgressDAObject(sessionCon, conn);
    try {
      MtmWorkflowStepUserActor mtmWorkflowStepUserActor = mtmWorkflowStepUserActorDAObject.getWorkflowStepUserActorByWorkflowStepID(workflowProgress.getWorkflowStepID());
      if (!Utility.isEmpty(mtmWorkflowStepUserActor)) {
        List workflowProgressList = workflowProgessDAO.getListByStepIDAndTrackID(workflowProgress.getWorkflowStepID(), workflowProgress.getTrackID());
        if (!Utility.isEmpty(workflowProgressList)) {
          WorkflowProgress currentProgress = (WorkflowProgress)workflowProgressList.get(0);
          List mtmUserRecordList = progressUserRecordDAO.getListByWorkflowProgressID(currentProgress.getID());
          for (int h = 0; !Utility.isEmpty(mtmUserRecordList) && h < mtmUserRecordList.size(); h++) {
            MtmWorkflowProgressUserRecord  mtmUserRecord = (MtmWorkflowProgressUserRecord)mtmUserRecordList.get(h);
            mtmUserRecord.setID(null);
            mtmUserRecord.setWorkflowProgressID(workflowProgress.getID());
            mtmUserRecord.setWorkflowAction(WorkflowProgress.STATUS_PENDING);
            mtmUserRecord = (MtmWorkflowProgressUserRecord)progressUserRecordDAO.insertObject(mtmUserRecord);
          }
          dynamicUserActorDAO.copyRecordByWorkflowProgressID(currentProgress.getID(), workflowProgress.getID());
        }
      }
    }catch (ApplicationException ex) {
      log.error(ex, ex);
    }
  }
  
  /**
   * File attachment to DMS
   * 
   * @param trackID The workflow track ID
   * @param conn The database connection
   * @param sessionCon
   * @throws ApplicationException
   */
  private void fileAttachmentToDMS (Integer trackID, Connection conn, SessionContainer sessionCon) throws ApplicationException {
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionCon, conn);
    WorkflowProgressAttachmentDAObject attachmentDAO = new WorkflowProgressAttachmentDAObject (sessionCon, conn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject (sessionCon, conn);
    WorkflowRecordDAObject recordDAO = new WorkflowRecordDAObject (sessionCon, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject( sessionCon, conn);
    DocumentOperationManager docOperationManager = new DocumentOperationManager( sessionCon, conn);
    MtmDocumentVersionDAObject mtmDocumentVersionDAObject = new MtmDocumentVersionDAObject( sessionCon, conn);
    
    List attachmentList = new ArrayList();
    List progressList = new ArrayList();
    List stepList = new ArrayList();
    Integer parentID = null;
    Integer rootID = null;
    DmsDocument trackIDFolder = null;
    WorkflowRecord record = null;
    progressList = progressDAO.getFinishedProgressListByTrackID(trackID);
    
    //Create Track ID Folder
    if(!Utility.isEmpty(progressList)){
      WorkflowProgress progress = (WorkflowProgress)progressList.get(0);
      WorkflowStep step = (WorkflowStep)stepDAO.getObjectByID(progress.getWorkflowStepID());
      record = (WorkflowRecord)recordDAO.getObjectByID(step.getWorkflowRecordID());
      
      //check set parentID or not
      if (!Utility.isEmpty(record.getParentID()) && record.getParentID().intValue() > 0 ) {
        parentID = record.getParentID();
        DmsDocument document = (DmsDocument)dmsDocumentDAO.getObjectByID(parentID);
        rootID = document.getRootID();
        
        attachmentList = attachmentDAO.getListByTrackID(trackID);
        //check hold attachment or not, and relate to Form Builder ro not
        if(!Utility.isEmpty(attachmentList) ||
            (SystemWorkflowConstant.FMB_SUBMISSION_BY_FORM.equals(record.getWorkflowCategoryID().toString()) ||
                SystemWorkflowConstant.FMB_SUBMISSION_BY_GROUP.equals(record.getWorkflowCategoryID().toString()) )  ){
          //create track folder
          DmsDocument dmsDocument = new DmsDocument();
          
          Integer length=SystemParameterFactory.getSystemParameterInteger(SystemParameterConstant.WORKLFLOW_TRACK_ID_FORMAT_LENGTH);
          String trickID=TextUtility.formatNumberWithZeroPrefix(length.intValue(),trackID);
          
          dmsDocument.setDocumentName("Track " + trickID);
          dmsDocument.setRecordStatus(GlobalConstant.STATUS_ACTIVE);
          dmsDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
          dmsDocument.setParentID(parentID);
          dmsDocument.setRootID(rootID);
          dmsDocument.setDocumentType(DmsDocument.FOLDER_TYPE);
          dmsDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
          trackIDFolder = docOperationManager.createFolder(dmsDocument);
        }
        
        //get the all Steps
        stepList = stepDAO.getListByWorkflowRecordID(record.getID());
      }
    }
    
    for (int k = 0; k < stepList.size(); k++) {
      WorkflowStep step = (WorkflowStep)stepList.get(k);
      progressList = progressDAO.getListByStepIDAndTrackID(step.getID(), trackID);
      
      for (int i = 0; !Utility.isEmpty(trackIDFolder) && i < progressList.size(); i++) {
        WorkflowProgress progress = (WorkflowProgress)progressList.get(i);
        //WorkflowStep step = (WorkflowStep)stepDAO.getObjectByID(progress.getWorkflowStepID());
        
        DmsDocument stepNameFolder = null;
        DmsDocument progressFolder = null;
        DmsDocument parentFolder = null;
        //get all attachment by workflow progress ID
        attachmentList = attachmentDAO.getListByWorkflowProgressID(progress.getID());
        
        //Create Step Name Folder
        //Add by samlin  stepNameFolder==null mean that the file alredy upload from AutoTaskFileUplodToDMS
        if(!Utility.isEmpty(attachmentList) && (stepNameFolder==null)){
          //check the stepNameFolder exist or not
          stepNameFolder = dmsDocumentDAO.getDocumentByNameParentID(step.getStepSeq() + "." + step.getStepName(), trackIDFolder.getID());
          if (Utility.isEmpty(stepNameFolder)) {
            DmsDocument dmsDocument = new DmsDocument();
            dmsDocument.setDocumentName(step.getStepSeq() + "." + getvalidFileName(step.getStepName()));
            dmsDocument.setRecordStatus(GlobalConstant.STATUS_ACTIVE);
            dmsDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
            dmsDocument.setParentID(trackIDFolder.getID());
            dmsDocument.setRootID(rootID);
            dmsDocument.setDocumentType(DmsDocument.FOLDER_TYPE);
            dmsDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
            stepNameFolder = docOperationManager.createFolder(dmsDocument);
            parentFolder = stepNameFolder;
          }
        } else {
          continue;
        }
        
        if (Utility.isEmpty(stepNameFolder)) {
          continue;
        } else if ( progressList.size() > 1) {
          //Create Progress Folder
          DmsDocument tmpDmsDocument = new DmsDocument();
          tmpDmsDocument.setDocumentName("Progress " + (i + 1));
          tmpDmsDocument.setRecordStatus(GlobalConstant.STATUS_ACTIVE);
          tmpDmsDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
          tmpDmsDocument.setParentID(stepNameFolder.getID());
          tmpDmsDocument.setRootID(rootID);
          tmpDmsDocument.setDocumentType(DmsDocument.FOLDER_TYPE);
          tmpDmsDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
          progressFolder = docOperationManager.createFolder(tmpDmsDocument);
          parentFolder = progressFolder;
        }
        
        log.debug("rootID:"+rootID);
        log.debug("stepNameFolder:"+stepNameFolder.getID()+":"+stepNameFolder.getDocumentName());
        log.debug("parentFolder:"+parentFolder.getID()+":"+parentFolder.getDocumentName());
        
        for (int j = 0; j < attachmentList.size(); j++){
          WorkflowProgressAttachment attachment = (WorkflowProgressAttachment)attachmentList.get(j);
          log.debug("attachment:"+attachment.getAttachmentName()+":"+attachment.getExternalID());
          
          if( WorkflowProgressAttachment.ATTACHED_SINGLE_FILE.equals(attachment.getAttachmentType()) ){
            //Create a new document
            String path = SystemParameterFactory.getSystemParameter(SystemParameterConstant.WORKFLOW_ATTACHMENT_PHYSICAL_PATH);
            //File attachedFile = new File(path + "/" + attachment.getExternalID());
            FileInputStream content = null;
            String allFileName="";
            try {
              
              allFileName = path + "/" + attachment.getExternalID();
              content = new FileInputStream(allFileName);
            } catch (FileNotFoundException fe){
              throw new ApplicationException("File not Found.");
            }
            String documentName = this.getNewFileName(attachment.getAttachmentName(), parentFolder.getID(), sessionCon, conn);
            DmsDocument dmsDocument = new DmsDocument();
            dmsDocument.setDocumentName(getvalidFileName(documentName));
            dmsDocument.setRecordStatus(GlobalConstant.STATUS_ACTIVE);
            dmsDocument.setItemStatus(DmsVersion.AVAILABLE_STATUS);
            dmsDocument.setParentID(parentFolder.getID());
            dmsDocument.setRootID(rootID);
            dmsDocument.setDocumentType(DmsDocument.DOCUMENT_TYPE);
            dmsDocument.setCreateType(DmsOperationConstant.DMS_CREATE_BY_SYSTEM);
            dmsDocument.setItemSize(attachment.getContentSize());
            try {
             // docOperationManager.createDocument(dmsDocument,content,true,null);
              DmsDocument newDocument= docOperationManager.createDocument(dmsDocument,content,true,null);
              attachment.setExternalID(newDocument.getVersionID().toString());
              attachment.setAttachmentType(WorkflowProgressAttachment.ATTACHED_DMS_VERSION_SYSTEM_ID);
              attachmentDAO.updateObject(attachment);
              File file =new File(allFileName);
              file.delete();
            } catch (com.dcivision.dms.core.DuplicateNameException dne){
              log.debug("duplicate name exception ");
              log.error(dne, dne);
            }
            
          } else if( WorkflowProgressAttachment.ATTACHED_DMS_VERSION_SYSTEM_ID.equals(attachment.getAttachmentType()) ){
            //Copy a document
            try {
              //check whether it is a compound document
            	 DmsDocument sourceDocument = (DmsDocument)mtmDocumentVersionDAObject.getDocumentByVersionID(new Integer(attachment.getExternalID()));
              if (this.checkIsCompoundDocument(new Integer(attachment.getExternalID()), conn, sessionCon) ) {
                //DmsDocument sourceDocument = (DmsDocument)mtmDocumentVersionDAObject.getDocumentByVersionID(new Integer(attachment.getExternalID()));
                String documentName = this.getNewFileName(sourceDocument.getDocumentName(), parentFolder.getID(), sessionCon, conn);
                sourceDocument.setParentID(parentFolder.getID());
                sourceDocument.setDocumentName(documentName);
                sourceDocument.setRootID(rootID);                
                docOperationManager.copyFolder(sourceDocument, parentFolder, rootID, "DMS.COPY_AS_NEW", DmsOperationConstant.COPY_ALL_VERSIONS, DmsOperationConstant.NO_STRUCTURE_COPY, true);
              } else if (DmsDocument.PAPER_DOC_TYPE.equals(sourceDocument.getDocumentType())) {
              	DmsDocument newDocument = null;
                synchronized (docOperationManager) {
                  try{
                  	sourceDocument.setParentID(parentFolder.getID());
                  	sourceDocument.setRootID(rootID);
                  	newDocument = docOperationManager.createWFPaperDocShortCut(sourceDocument);
                  } catch ( ApplicationException ae ) {
                    // ignore
                    log.error(ae, ae);
                  }
                }
                /*
                String documentName = this.getNewFileName(newDocument.getDocumentName(), parentFolder.getID(), sessionCon, conn);
                newDocument.setDocumentName(documentName);
                //newDocument.setParentID(parentFolder.getID());
                //newDocument.setRootID(rootID);
                synchronized (docOperationManager) {
                  docOperationManager.moveDocument(newDocument, parentFolder, parentFolder.getRootID());
                }
                */
              } else {
               // DmsDocument sourceDocument = (DmsDocument)mtmDocumentVersionDAObject.getDocumentByVersionID(new Integer(attachment.getExternalID()));
                String documentName = this.getNewFileName(attachment.getAttachmentName(), parentFolder.getID(), sessionCon, conn);
                attachment.setAttachmentName(documentName);
                docOperationManager.copyDocumentByVersionIDForWF(parentFolder,rootID,"DMS.COPY_AS_NEW", new Integer(attachment.getExternalID()),true);
              }
            } catch (com.dcivision.dms.core.DuplicateNameException dne){
              log.debug("duplicate name exception ");
            }
          }
        }
        
      }
      
    }
    
    //handle the form file.
    if( !Utility.isEmpty(record) &&
        (SystemWorkflowConstant.FMB_SUBMISSION_BY_FORM.equals(record.getWorkflowCategoryID().toString()) ||
            SystemWorkflowConstant.FMB_SUBMISSION_BY_GROUP.equals(record.getWorkflowCategoryID().toString())) ){
      
      MtmWorkflowProgressSystemObjectDAObject objectDAO = new MtmWorkflowProgressSystemObjectDAObject(sessionCon, conn);       
      FormSubmissionDAObject submissionDAO = new FormSubmissionDAObject(sessionCon, conn);
      
      List submissionList = objectDAO.getListByTrackID(trackID);  
      
      for (int i=0; i<submissionList.size(); i++) {
        MtmWorkflowProgressSystemObject object = (MtmWorkflowProgressSystemObject)submissionList.get(i);  
        
        FormSubmission formSubmission = (FormSubmission)submissionDAO.getObjectByID(object.getObjectID());
        
        FormSubmissionManager formManager = new FormSubmissionManager(sessionCon, conn);
        Integer formUploadPath = formSubmission.getDmsParentID();
        
        log.debug("Form Upload Path:" + formUploadPath);
        //create Form File For Form Builder
        if (!Utility.isEmpty(formUploadPath) && formUploadPath.intValue()>0) {          
          //This conn upadate some table must be commited before other conn use these table           
          try {
            conn.commit();
          } catch (SQLException exp) {
            log.error("DB Connection Commit Fail.",exp);
          }
          
          log.debug("Upload Form File For Form Builder.");
          DmsDocument formParentFolder = (DmsDocument)dmsDocumentDAO.getObjectByID(formSubmission.getDmsParentID());
          formManager.saveFileToDMS(formSubmission.getID(), formParentFolder.getRootID().toString(), formParentFolder.getID().toString(), true);
        }
        
        //create Form File For WorkflowFlow
        if (!Utility.isEmpty(parentID) && !Utility.isEmpty(rootID)) {          
          //This conn upadate some table must be commited before other conn use these table          
          try {
            conn.commit();
          } catch (SQLException exp) {
            log.error("DB Connection Commit Fail.",exp);
          }
          
          log.debug("Upload Form File For Workflow.");
          formManager.saveFileToDMS(formSubmission.getID(), rootID.toString(), trackIDFolder.getID().toString(), true);
        }
      }
    }
  }
  
  /**
   * check whether it is a compound document.
   * 
   * @param versionID The workflow record version ID
   * @param conn The database connection
   * @param sessionCon
   * @return boolean
   * @throws ApplicationException
   */
  private boolean checkIsCompoundDocument(Integer versionID, Connection conn, SessionContainer sessionCon) throws ApplicationException {
    DmsVersionDAObject dmsVersionDAO = new DmsVersionDAObject(sessionCon, conn);
    DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject( sessionCon, conn);
    DmsVersion dmsVersion = (DmsVersion)dmsVersionDAO.getObjectByID(versionID);
    
    DmsDocument dmsDoc = (DmsDocument)dmsDocumentDAO.getObjectByID(dmsVersion.getDocumentID());
    
    if( DmsDocument.COMPOUND_DOC_TYPE.equals(dmsDoc.getDocumentType()) ){
      return true;
    }
    return false;
  }

  /**
  * Gets a string of new file name for given old file name ,workflow step parent , session and database connection
  *
  * @param oldFileName
  * @param parentID 
  * @param sessionContainer
  * @param conn The database connection
  * @throws ApplicationException
  */
  public String getNewFileName(String oldFileName,Integer parentID,SessionContainer sessionContainer,Connection conn) throws ApplicationException{  
    if(checkDuplicateFileName(oldFileName,parentID,sessionContainer,conn)){
      String fileExten = oldFileName.substring(oldFileName.lastIndexOf("."), oldFileName.length());
      log.debug("the fileExten is " + fileExten);
      String newFileName="";
      String copyFlag = MessageResourcesFactory.getMessage(sessionContainer.getSessionLocale(), "common.label.copy");
      int openBracket = oldFileName.indexOf(copyFlag + "(");
      int closeBracket = -1;
      if (openBracket >= 0) {
        closeBracket = oldFileName.indexOf(")");
      }
      String numberStr="0";
      if(openBracket>=0 && closeBracket-1>=0){
        numberStr = oldFileName.substring(closeBracket-1,closeBracket);
      }
      try{
       // int numberInt = TextUtility.parseInteger(numberStr);
        int numberInt=Integer.parseInt(numberStr);
        newFileName += copyFlag + "(" + (numberInt+1) + ")" + oldFileName.substring(closeBracket + 1,oldFileName.length());  
        if(newFileName.length()>80){
          newFileName=newFileName.substring(0,80-fileExten.length()-1) + fileExten;    
        }
      }catch(Exception e){
        //not a valid file naming pattern, add a new (1) at the end
        //e.g. development guide (hong kong).txt -> developement guide (hong kong)(1).txt
        newFileName += copyFlag + "(1)" + oldFileName.substring(closeBracket + 1,oldFileName.length());  
        if(newFileName.length()>80){
          newFileName=newFileName.substring(0,80-fileExten.length()-1) + fileExten;    
        }
      } 
      //recursive check file name
      return getNewFileName(newFileName,parentID,sessionContainer,conn);
    }else{
      return oldFileName;
    }
  }
   
  public boolean checkDuplicateFileName(String fileName,Integer parentID,SessionContainer sessionContainer,Connection conn) throws ApplicationException{
    DmsDocumentDAObject dmsDocumentDAO=new DmsDocumentDAObject(sessionContainer,conn);
    DmsDocument dmsDocument=dmsDocumentDAO.getDocumentByNameParentID(fileName,parentID);
    if(!Utility.isEmpty(dmsDocument)){
      return true;   
    }else{
      return false;   
    }
    
  }

  private String getvalidFileName(String fileName) {
    String sysInvalidCharacters=SystemParameterFactory.getSystemParameter(SystemParameterConstant.INVALID_CHARACTER);
    StringTokenizer stringToken=new StringTokenizer(sysInvalidCharacters,",");
    while (stringToken.hasMoreTokens()){
        String invalidChar=stringToken.nextToken().trim();
        if (fileName.indexOf(invalidChar)!= -1){
            fileName=TextUtility.replaceString(fileName,invalidChar,"");
        }
    }
    return fileName;
  }
}
